package com.fablesoft.projectdatacollect.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;

public class BitmapCache {

    /**
     * Get bitmap from cache.
     * 
     * @param cacheName
     *            The file name in cache dir which need to get.
     * */
    public static InputStream getBitmapFromCache(Context context,
            String cacheName) {
        if (cacheName == null || cacheName.trim().equals("")) {
            return null;
        }
        File file = new File(context.getCacheDir(), cacheName);
        FileInputStream inStream = null;
        LogUtil.v("marico", "file : " + file);
        if (!file.exists()) {
            return null;
        }
        try {
            inStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            Log4jUtil.e(e.toString());
            e.printStackTrace();
        }
        return inStream;
    }

    public static Bitmap getBitmapFromFile(File dst, int width, int height) {  
	    if (null != dst && dst.exists()) {  
	        BitmapFactory.Options opts = null;  
	        if (width > 0 && height > 0) {  
	            opts = new BitmapFactory.Options();  
	            opts.inJustDecodeBounds = true;  
	            BitmapFactory.decodeFile(dst.getPath(), opts);  
	            // 计算图片缩放比例  
	            final int minSideLength = Math.min(width, height);  
	            opts.inSampleSize = computeSampleSize(opts, minSideLength,  
	                    width * height);  
	            opts.inJustDecodeBounds = false;  
	            opts.inInputShareable = true;  
	            opts.inPurgeable = true;  
	        }  
	        try {  
	            return BitmapFactory.decodeFile(dst.getPath(), opts);  
	        } catch (OutOfMemoryError e) {  
	            e.printStackTrace();  
	        }  
	    }  
	    return null;  
	}
    
    public static int computeSampleSize(BitmapFactory.Options options,  
            int minSideLength, int maxNumOfPixels) {  
        int initialSize = computeInitialSampleSize(options, minSideLength,  
                maxNumOfPixels);  
      
        int roundedSize;  
        if (initialSize <= 8) {  
            roundedSize = 1;  
            while (roundedSize < initialSize) {  
                roundedSize <<= 1;  
            }  
        } else {  
            roundedSize = (initialSize + 7) / 8 * 8;  
        }  
      
        return roundedSize;  
    }  
      
    private static int computeInitialSampleSize(BitmapFactory.Options options,  
            int minSideLength, int maxNumOfPixels) {  
        double w = options.outWidth;  
        double h = options.outHeight;  
      
        int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math  
                .sqrt(w * h / maxNumOfPixels));  
        int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math  
                .floor(w / minSideLength), Math.floor(h / minSideLength));  
      
        if (upperBound < lowerBound) {  
            // return the larger one when there is no overlapping zone.  
            return lowerBound;  
        }  
      
        if ((maxNumOfPixels == -1) && (minSideLength == -1)) {  
            return 1;  
        } else if (minSideLength == -1) {  
            return lowerBound;  
        } else {  
            return upperBound;  
        }  
    } 
    
    /**
     * Save bitmap to cache.
     * 
     * @param cacheName
     *            The cache file name need to save.
     *            which bitmap ByteArray need to save.
     * */
    public static void saveBitmapToCache(Context context, String cacheName,
            ByteArrayOutputStream baos) {
        LogUtil.v("marico", "saveBitmapToCache cacheName : "
                + cacheName);
        File file = new File(context.getCacheDir(), cacheName);
        FileOutputStream outStream = null;
        try {
            file.createNewFile();
            outStream = new FileOutputStream(file);
            baos.writeTo(outStream);
            outStream.flush();
            outStream.close();
        } catch (IOException e) {
            Log4jUtil.e(e.toString());
            e.printStackTrace();
        }
    }

    /**
     * Save bitmap to cache.
     * 
     * @param cacheName
     *            The cache file name need to save.
     * @param bitmap
     *            which bitmap need to save.
     * */
    public static void saveBitmapToCache(Context context, String cacheName,
            Bitmap bitmap) {
        LogUtil.v("marico", "urlStr : " + cacheName);
        File file = new File(context.getCacheDir(), cacheName);
        FileOutputStream outStream = null;
        try {
            file.createNewFile();
            outStream = new FileOutputStream(file);
            bitmap.compress(CompressFormat.JPEG, 100, outStream);
            outStream.close();
        } catch (IOException e) {
            Log4jUtil.e(e.toString());
            e.printStackTrace();
        }
    }

    /**
     * Compress bitmap. This method will compress bitmap to < 500K
     * */
    public static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 100;
        while (baos.toByteArray().length / 1024 > 500) {
            baos.reset();
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            options -= 10;
            if (options <= 0) {
                break;
            }
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
        return bitmap;
    }
    
    /**
     * Compress bitmap. This method will compress bitmap to < 500K
     * */
    public static Bitmap compressImage2small(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 100;
        while (baos.toByteArray().length / 1024 > 5) {
            baos.reset();
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            options -= 10;
            if (options <= 0) {
                break;
            }
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
        return bitmap;
    }

    /**
     * Compress bitmap. This method will compress bitmap to < 5000K
     * */
    public static Bitmap compressImage(Context context,
            ByteArrayOutputStream baos) {
        ActivityManager am = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);

        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        am.getMemoryInfo(mi);
        long availMem = mi.availMem / (1024 * 1024);
        LogUtil.v("marico", "availMem : " + availMem);
        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
        long baosLength = baos.size() / 1024;
        LogUtil.v("marico", "baos.size() : " + baosLength);
        if (availMem < 50 && baosLength > 1000) {
            bitmapOptions.inSampleSize = 8;
        } else if (availMem < 50 && baosLength > 500) {
            bitmapOptions.inSampleSize = 2;
        } else if (availMem < 100 && baosLength > 1000) {
            bitmapOptions.inSampleSize = 4;
        } else if (availMem < 100 && baosLength > 500) {
            bitmapOptions.inSampleSize = 2;
        } else if (availMem < 500 && baosLength > 1000) {
            bitmapOptions.inSampleSize = 2;
        }

        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        Bitmap image = BitmapFactory.decodeStream(isBm, null, bitmapOptions);
        try {
            isBm.close();
        } catch (IOException e) {
            Log4jUtil.e(e.toString());
            e.printStackTrace();
        }
        isBm = null;
        // Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0,
        // byteArray.length);
        baos.reset();
        try{
            image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        } catch (Exception ex){
            Log4jUtil.e(ex.toString());
            ex.printStackTrace();
            try {
                throw new Exception("image.compress is null");
            } catch (Exception e) {
                Log4jUtil.e(e.toString());
                e.printStackTrace();
                return null;
            }
        }
        
        int options = 100;
        while (baos.toByteArray().length / 1024 > 5000) {
            baos.reset();
            try{
                image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            } catch (Exception ex){
                Log4jUtil.e(ex.toString());
                ex.printStackTrace();
                throw new RuntimeException("image.compress is null");
            }
            
            options -= 5;
            LogUtil.v("marico", "options : " + options);
            if (options <= 0) {
                break;
            }
        }
        image.recycle();
        image = null;
        System.gc();
        isBm = new ByteArrayInputStream(baos.toByteArray());
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
        try {
            isBm.close();
        } catch (IOException e) {
            Log4jUtil.e(e.toString());
            e.printStackTrace();
        }
        isBm = null;
        return bitmap;
    }

    /**
     * If exit application, need call this method to clear cache.
     * */
    public static void clearCache(Context context) {
        File cache = context.getCacheDir();
        for (File child : cache.listFiles()) {
            child.delete();
        }
    }

}
